// PBS Server is a http/https proxy balancer, used for select best proxies automaticly.
package main

import (
	"fmt"
	"io"
	"net"
	"os"
)

func main() {
	// get args and any other things
	var configPath string
	processPBSArgs(os.Args, &configPath)

	// parse args
	var config Config
	var proxiesArr []string
	parseConfig(&configPath, &config, &proxiesArr)

	// get proxy array with weight
	var proxiesObj []*Proxy
	getProxiesObj(&proxiesObj, proxiesArr)

	// duplicate an array of Proxy Pointer for wrr
	currentProxies := *new([]*Proxy)

	// init proxies
	initProxies(&currentProxies, &proxiesObj, &config)

	// proxies health check
	if config.CheckEnabled {
		go checkProxies(&currentProxies, &proxiesObj, &config)
	}

	// start a port listen
	port := fmt.Sprintf(":%d", config.Port)
	listener, err := net.Listen("tcp", port)
	if err != nil {
		fmt.Printf("PBS Server failed to start, err: %s\n", err.Error())
		return
	}
	fmt.Printf("PBS server listening on %d...\n", config.Port)

	for {
		// get all connect
		client, err := listener.Accept()
		if err != nil {
			fmt.Printf("Connection error, err: %s\n", err.Error())
		}
		go handleRequest(client, &currentProxies)
	}
}

func handleRequest(client net.Conn, currentProxies *[]*Proxy) {
	// Dial to certain proxy
	bestProxy := getBestProxy(currentProxies)
	proxy, err := net.Dial("tcp", bestProxy.addr)

	if err != nil {
		fmt.Printf("Dial to %s error, err: %s\n", bestProxy.addr, err.Error())
		return
	}

	defer func() {
		_ = client.Close()
		_ = proxy.Close()
	}()

	// everything is ready, transfer data
	// write data from proxy to client parallel
	// TODO tcp keepalive: use of closed network connection wile close the connection
	go func() {
		_, _ = io.Copy(client, proxy)
	}()

	// write data from client to proxy
	_, _ = io.Copy(proxy, client)
}